/*******************************************************************************
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2005, 2008. All Rights Reserved. 
 * 
 * Note to U.S. Government Users Restricted Rights:  Use, 
 * duplication or disclosure restricted by GSA ADP Schedule 
 * Contract with IBM Corp.
 *******************************************************************************/

package org.eclipsecon.dui.interpreter.internal;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
import org.eclipsecon.dui.swtmodel.Constant;
import org.eclipsecon.dui.swtmodel.MActionHandler;
import org.eclipsecon.dui.swtmodel.MButton;
import org.eclipsecon.dui.swtmodel.MColor;
import org.eclipsecon.dui.swtmodel.MCombo;
import org.eclipsecon.dui.swtmodel.MComposite;
import org.eclipsecon.dui.swtmodel.MControl;
import org.eclipsecon.dui.swtmodel.MFont;
import org.eclipsecon.dui.swtmodel.MGridData;
import org.eclipsecon.dui.swtmodel.MGridLayout;
import org.eclipsecon.dui.swtmodel.MLabel;
import org.eclipsecon.dui.swtmodel.MModel;
import org.eclipsecon.dui.swtmodel.MSWT;
import org.eclipsecon.dui.swtmodel.MText;
import org.eclipsecon.dui.swtmodel.Parameter;
import org.eclipsecon.dui.swtmodel.Template;
import org.eclipsecon.dui.swtmodel.TemplateUsage;
import org.eclipsecon.dui.swtmodel.Variable;
import org.eclipsecon.dui.swtmodel.util.SwtmodelSwitch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class HTMLModelSwitch extends SwtmodelSwitch {
	private final Browser fBrowser;
	private final ModelContext fContext;
	private TemplateUsage fTemplate;
	private final StringBuilder fBuilder;
	private MComposite fComposite;

	static class HtmlSnippet {
		private String fHtml;
		private int fColspan;

		public HtmlSnippet(int colspan, String html) {
			super();
			fColspan= colspan;
			fHtml= html;
		}

		static HtmlSnippet create(String html, int colspan) {
			return new HtmlSnippet(colspan, html);
		}

		public String getHtml() {
			return fHtml;
		}

		public int getColspan() {
			return fColspan;
		}
	}

	private static Map<MComposite, List<HtmlSnippet>> fMapCompositeToHTML= new HashMap<MComposite, List<HtmlSnippet>>();

	public HTMLModelSwitch(MComposite composite, Browser parent, StringBuilder builder, ModelContext context) {
		if (composite == null)
			fMapCompositeToHTML.clear();
		fBrowser= parent;
		fBuilder= builder;
		fContext= context;
		fComposite= composite;
	}

	private HTMLModelSwitch(MComposite composite, Browser parent, StringBuilder builder, ModelContext context, TemplateUsage template) {
		this(composite, parent, builder, context);
		fTemplate= template;
	}

	@Override
	public Object caseMModel(MModel object) {
		return doSwitch(object.getRootComposite());
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMComposite(org.eclipsecon
	 * .dui.model.MComposite)
	 */
	@Override
	public Object caseMComposite(MComposite object) {

		/* Create "Widgets" */
		HTMLModelSwitch modelSwitch= new HTMLModelSwitch(object, fBrowser, fBuilder, fContext);
		EList<MControl> children= object.getChildren();
		for (MControl child : children) {
			modelSwitch.doSwitch(child);
		}

		/* Layout "Widgets" */
		int numCols= 1;
		if (object.getLayout() != null)
			numCols= (Integer) doSwitch(object.getLayout());

		int curCol= 1;

		List<HtmlSnippet> listOfHTML= fMapCompositeToHTML.get(object);
		if (listOfHTML != null && !listOfHTML.isEmpty()) {
			fBuilder.append("<table cellpadding='2' cellspacing='5' ").append(getCSS(object)).append(">");

			for (int i= 0; i < listOfHTML.size(); i++) {
				HtmlSnippet snippet= listOfHTML.get(i);

				if (curCol == 1)
					fBuilder.append("<tr>");

				fBuilder.append("<td colspan=\"" + snippet.getColspan() + "\">");
				fBuilder.append(snippet.getHtml());
				fBuilder.append("</td>");

				curCol+= snippet.getColspan();

				if (curCol > numCols) {
					curCol= 1;
					fBuilder.append("</tr>");
				}
			}

			fBuilder.append("</table>");
		}

		return new Object();
	}

	public void layout() {

	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMColor(org.eclipsecon.dui
	 * .model.MColor)
	 */
	@Override
	public Object caseMColor(MColor object) {
		return "rgb(" + object.getRed() + ", " + object.getBlue() + ", " + object.getGreen() + ");";
	}

	/**
	 * @param object
	 * @return
	 */
	@Override
	public Object caseMFont(MFont object) {
		String css= "";

		String name= object.getName();
		int height= object.getHeight();

		if (name != null)
			css+= "font-family: " + name + "; ";

		if (height > 0)
			css+= "font-size: " + height + "pt; ";

		EList<MSWT> style= object.getStyle();
		if (style.contains(MSWT.BOLD))
			css+= "font-weight: bold; ";
		if (style.contains(MSWT.ITALIC))
			css+= "font-style: italic; ";

		return css;
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMButton(org.eclipsecon.
	 * dui.model.MButton)
	 */
	@Override
	public Object caseMButton(MButton object) {
		StringBuilder html= new StringBuilder();
		html.append("<input ").append(getCSS(object)).append(" type='button' value='").append((String) doSwitch(object.getName())).append("' />");

		Integer colspan= 1;
		if (object.getLayoutdata() != null)
			colspan= (Integer) doSwitch(object.getLayoutdata());

		putHtml(html, colspan);

		return new Object();
	}

	private void putHtml(StringBuilder html, int colspan) {
		List<HtmlSnippet> list= fMapCompositeToHTML.get(fComposite);
		if (list == null) {
			list= new ArrayList<HtmlSnippet>();
			fMapCompositeToHTML.put(fComposite, list);
		}
		list.add(HtmlSnippet.create(html.toString(), colspan));
	}

	/*
	 * @see
	 * org.eclipsecon.dui.swtmodel.util.SwtmodelSwitch#caseMCombo(org.eclipsecon
	 * .dui.swtmodel.MCombo)
	 */
	@Override
	public Object caseMCombo(MCombo object) {
		StringBuilder html= new StringBuilder();

		html.append("<select ").append(getCSS(object)).append(">");
		for (Parameter param : object.getValues()) {
			html.append("<option>").append((String) doSwitch(param)).append("</option>");
		}
		html.append("</select>");

		Integer colspan= 1;
		if (object.getLayoutdata() != null)
			colspan= (Integer) doSwitch(object.getLayoutdata());

		putHtml(html, colspan);

		return new Object();
	}

	@Override
	public Object caseMActionHandler(MActionHandler object) {
		return new Object();
	}

	@Override
	public Object caseTemplateUsage(TemplateUsage object) {
		Map<String, String> parameterMapping= new HashMap<String, String>();
		int i= 0;
		for (String s : object.getTemplate().getVariables()) {
			parameterMapping.put(s, object.getParameters().get(i));
			i++;
		}

		TreeIterator<EObject> allContents= object.getTemplate().eAllContents();
		for (Iterator<EObject> iterator= allContents; iterator.hasNext();) {
			EObject o= iterator.next();
			if (o instanceof Variable) {
				Variable var= (Variable) o;
				String value= var.getValue();
				var.setActualValue(parameterMapping.get(value));
			}

		}

		HTMLModelSwitch ms= new HTMLModelSwitch(fComposite, fBrowser, fBuilder, fContext, object);
		for (MControl control : object.getTemplate().getWidgets()) {
			ms.doSwitch(control);
		}

		return null;
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMLabel(org.eclipsecon.dui
	 * .model.MLabel)
	 */
	@Override
	public Object caseMLabel(MLabel object) {
		StringBuilder html= new StringBuilder();
		html.append("<span ").append(getCSS(object)).append(">").append((String) doSwitch(object.getName())).append("</span>");

		Integer colspan= 1;
		if (object.getLayoutdata() != null)
			colspan= (Integer) doSwitch(object.getLayoutdata());

		putHtml(html, colspan);

		return new Object();
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMText(org.eclipsecon.dui
	 * .model.MText)
	 */
	@Override
	public Object caseMText(MText object) {
		StringBuilder html= new StringBuilder();

		if (object.getValue() != null)
			html.append("<input ").append(getCSS(object)).append(" type='text' value='").append((String) doSwitch(object.getValue())).append("' />");
		else
			html.append("<input ").append(getCSS(object)).append(" type='text' />");

		Integer colspan= 1;
		if (object.getLayoutdata() != null)
			colspan= (Integer) doSwitch(object.getLayoutdata());

		putHtml(html, colspan);

		return new Object();
	}

	@Override
	public Object caseConstant(Constant object) {
		return object.getValue();
	}

	@Override
	public Object caseVariable(Variable object) {
		return object.getActualValue();
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMGridLayout(org.eclipsecon
	 * .dui.model.MGridLayout)
	 */
	@Override
	public Object caseMGridLayout(MGridLayout object) {
		return object.getNumColumns();
	}

	/*
	 * @see
	 * org.eclipsecon.dui.model.util.ModelSwitch#caseMGridData(org.eclipsecon
	 * .dui.model.MGridData)
	 */
	@Override
	public Object caseMGridData(MGridData object) {
		//		GridData data= new GridData();
		//		data.horizontalAlignment= object.getHorizontalAlignment().getValue();
		//		data.verticalAlignment= object.getVerticalAlignment().getValue();
		//		data.grabExcessHorizontalSpace= object.isGrabExcessHorizontalSpace();
		//		data.grabExcessVerticalSpace= object.isGrabExcessVerticalSpace();
		//		data.horizontalSpan= object.getHorizontalSpan();
		//		data.verticalSpan= object.getVerticalSpan();
		//		data.widthHint= object.getWidthHint();
		//		data.heightHint= object.getHeightHint();
		//
		//		return data;

		//		String css= "";
		//
		//		if (object.getWidthHint() > 0)
		//			css+= " width: " + object.getWidthHint() + "px;";
		//
		//		if (object.getHeightHint() > 0)
		//			css+= " height: " + object.getHeightHint() + "px;";

		return object.getHorizontalSpan();
	}

	private String getCSS(MControl mControl) {
		StringBuilder css= new StringBuilder("style='");

		if (mControl.getBackground() != null) {
			String bgColor= (String) doSwitch(mControl.getBackground());
			css.append("background-color: ").append(bgColor);
		}

		if (mControl.getForeground() != null) {
			String fgColor= (String) doSwitch(mControl.getForeground());
			css.append("color: ").append(fgColor);
		}

		if (mControl.getFont() != null) {
			String font= (String) doSwitch(mControl.getFont());
			css.append(font);
		}

		//		if (mControl.getLayoutdata() != null) {
		//			String layoutData= (String) doSwitch(mControl.getLayoutdata());
		//			css.append(layoutData);
		//		}

		css.append("'");

		return css.toString();
	}

	private void applyAdaper(MControl mControl, Control control) {
		if (!(mControl.eContainer() instanceof Template)) {
			mControl.eAdapters().add(new SWTControlAdapter(control));
		} else {
			SWTControlAdapter adapter= (SWTControlAdapter) EcoreUtil.getAdapter(mControl.eAdapters(), SWTControlAdapter.class);
			if (adapter == null) {
				adapter= new SWTControlAdapter();
				mControl.eAdapters().add(adapter);
			}
			adapter.setControl(fTemplate, control);
		}
	}

	private void applyLayoutData(MControl mControl, Control control) {
		if (mControl.getLayoutdata() != null) {
			Object data= doSwitch(mControl.getLayoutdata());
			control.setLayoutData(data);
		}
	}

	private void applyLayout(MComposite mComposite, Composite composite) {
		if (mComposite.getLayout() != null) {
			Layout layout= (Layout) doSwitch(mComposite.getLayout());
			composite.setLayout(layout);
		}
	}
}
